{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "8cc39cad",
   "metadata": {},
   "source": [
    "# 실험(Experiment) 평가 비교\n",
    "\n",
    "LangSmith 에서 제공하는 Compare 기능을 활용하여 실험 결과를 쉽게 비교할 수 있습니다.\n",
    "\n",
    "**참고**\n",
    "- https://docs.smith.langchain.com/cookbook/tracing-examples/traceable#using-the-decorator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "34a30a84",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 설치\n",
    "# !pip install -qU langsmith langchain-teddynote"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d75d1492",
   "metadata": {},
   "outputs": [],
   "source": [
    "# API KEY를 환경변수로 관리하기 위한 설정 파일\n",
    "from dotenv import load_dotenv\n",
    "\n",
    "# API KEY 정보로드\n",
    "load_dotenv()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "633d9db2",
   "metadata": {},
   "outputs": [],
   "source": [
    "# LangSmith 추적을 설정합니다. https://smith.langchain.com\n",
    "# !pip install -qU langchain-teddynote\n",
    "from langchain_teddynote import logging\n",
    "\n",
    "# 프로젝트 이름을 입력합니다.\n",
    "logging.langsmith(\"CH16-Evaluations\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a09c8411",
   "metadata": {},
   "source": [
    "## RAG 성능 테스트를 위한 함수 정의"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "011f17eb",
   "metadata": {},
   "source": [
    "테스트에 활용할 RAG 시스템을 생성하겠습니다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9bb9be51",
   "metadata": {},
   "outputs": [],
   "source": [
    "from myrag import PDFRAG\n",
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "\n",
    "# 질문에 대한 답변하는 함수를 생성\n",
    "def ask_question_with_llm(llm):\n",
    "    # PDFRAG 객체 생성\n",
    "    rag = PDFRAG(\n",
    "        \"data/SPRI_AI_Brief_2023년12월호_F.pdf\",\n",
    "        llm,\n",
    "    )\n",
    "\n",
    "    # 검색기(retriever) 생성\n",
    "    retriever = rag.create_retriever()\n",
    "\n",
    "    # 체인(chain) 생성\n",
    "    rag_chain = rag.create_chain(retriever)\n",
    "\n",
    "    def _ask_question(inputs: dict):\n",
    "        context = retriever.invoke(inputs[\"question\"])\n",
    "        context = \"\\n\".join([doc.page_content for doc in context])\n",
    "        return {\n",
    "            \"question\": inputs[\"question\"],\n",
    "            \"context\": context,\n",
    "            \"answer\": rag_chain.invoke(inputs[\"question\"]),\n",
    "        }\n",
    "\n",
    "    return _ask_question"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bb60ff88",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_ollama import ChatOllama\n",
    "\n",
    "# Ollama 모델을 불러옵니다.\n",
    "ollama = ChatOllama(model=\"EEVE-Korean-10.8B:latest\")\n",
    "\n",
    "# Ollama 모델 호출\n",
    "ollama.invoke(\"안녕하세요?\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5549f7aa",
   "metadata": {},
   "source": [
    "GPT-4o-mini 모델과 Ollama 모델을 활용하여 질문에 대한 답변을 생성하는 함수를 생성합니다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c95e0cd6",
   "metadata": {},
   "outputs": [],
   "source": [
    "gpt_chain = ask_question_with_llm(ChatOpenAI(model=\"gpt-4o-mini\", temperature=0))\n",
    "ollama_chain = ask_question_with_llm(ChatOllama(model=\"EEVE-Korean-10.8B:latest\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c0e1a889",
   "metadata": {},
   "source": [
    "GPT-4o-mini 모델과 Ollama 모델을 활용한 답변 평가를 진행합니다.\n",
    "\n",
    "2개의 체인에 대하여 각각 진행합니다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ab2fb1c0",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langsmith.evaluation import evaluate, LangChainStringEvaluator\n",
    "\n",
    "# qa 평가자 생성\n",
    "cot_qa_evalulator = LangChainStringEvaluator(\n",
    "    \"cot_qa\",\n",
    "    config={\"llm\": ChatOpenAI(model=\"gpt-4o-mini\", temperature=0)},\n",
    "    prepare_data=lambda run, example: {\n",
    "        \"prediction\": run.outputs[\"answer\"],\n",
    "        \"reference\": run.outputs[\"context\"],\n",
    "        \"input\": example.inputs[\"question\"],\n",
    "    },\n",
    ")\n",
    "\n",
    "dataset_name = \"RAG_EVAL_DATASET\"\n",
    "\n",
    "# 평가 실행\n",
    "experiment_results1 = evaluate(\n",
    "    gpt_chain,\n",
    "    data=dataset_name,\n",
    "    evaluators=[cot_qa_evalulator],\n",
    "    experiment_prefix=\"MODEL_COMPARE_EVAL\",\n",
    "    # 실험 메타데이터 지정\n",
    "    metadata={\n",
    "        \"variant\": \"GPT-4o-mini 평가 (cot_qa)\",\n",
    "    },\n",
    ")\n",
    "\n",
    "# 평가 실행\n",
    "experiment_results2 = evaluate(\n",
    "    ollama_chain,\n",
    "    data=dataset_name,\n",
    "    evaluators=[cot_qa_evalulator],\n",
    "    experiment_prefix=\"MODEL_COMPARE_EVAL\",\n",
    "    # 실험 메타데이터 지정\n",
    "    metadata={\n",
    "        \"variant\": \"Ollama(EEVE-Korean-10.8B:latest) 평가 (cot_qa)\",\n",
    "    },\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6dc3f5a7",
   "metadata": {},
   "source": [
    "결과를 검사하기 위해 비교 보기를 사용하십시오."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cec2709e",
   "metadata": {},
   "source": [
    "**비교 보기를 하는 방법**\n",
    "\n",
    "![](./assets/eval-01.png)\n",
    "\n",
    "![](./assets/eval-02.png)\n",
    "\n",
    "1. Dataset 의 Experiment 탭에서 비교하고 싶은 실험을 선택합니다.\n",
    "2. 하단의 \"Compare\" 버튼을 클릭합니다.\n",
    "3. 비교 보기가 표시됩니다."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "langchain-kr-lwwSZlnu-py3.11",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
